/*
 * sprite.c
 *
 * General sprite and sprite-like functions, including
 * animations and fonts.
 *
 */

#define _SPRITE_
//#define TESTADDON
#define TRUE  1
#define FALSE 0

#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>

#include "rad.h"
#include "event.h"
#include "xenon.h"
#include "sprite.h"
#include "player.h"
#include "palette.h"
#include "debug.h"
#include "sound.h"

/* Globals */

void            SpriteAddOnScreen(long spritenum, TARGET * spritetarg);
TARGET         *SpriteDelOnScreen(TARGET * spritetodel);
void            SpritePlaceOnScreen(u8 * smackerbuf);

long            g_testamtreq=0;
TARGET         *g_SpritesOnScreen = (TARGET *) NULL;
extern TARGET   g_targstack[];
extern TARGETCLASS g_classtack[];
extern char     g_typeofdeath;
extern long     g_curframe;
extern long     g_currentscenenumber;
extern blitpic  g_damg;
extern char    *g_imagebuffer;
extern char    *g_targetcolor;


long           *g_planeoffsets; /* Bit plane offsets for mode-x */
long            g_numsprites;   /* Number of sprites */
u8             *g_spritepalette;/* pointer to sprite palette */
shot            g_shot[MAXSHOTS + 1];   /* Array of player shot info */
ani             g_ani[MAXANIS + 1];     /* Array of 2D-animation info */
xfont           g_font[256];    /* Font data */
char            g_asciimap[256];/* Map of ASCII-font index */
/*extern long g_newxoff,g_newyoff;*/

delaysprite     g_pastein[NUMSPRITECHANNELS];

extern sprite  *g_ramsprites;
/* Function Defs */

long            initsprites();
void            ResetSpritePalette(u8 * where, long spritebase);
void            oldepastesprite(spriteptr s, u8 * screen, u8 * spritebuffer, short x, short y);
void            plotshot(u8 * buffer, shotptr s);
void            print4(short x, short y, char *s, blitpicptr b);
int             startani(spriteptr * s, short x, short y, long numframes, short dx, short dy);
void            updateshots(u8 * buffer);
long            startshot(short x, short y, short tx, short ty, short numframes);
pasteblt(u8 * buffer, blitpicptr b);
void            printx(short x, short y, char *s, u8 * buffer);
pastechar(xfontptr f, short x, short y, u8 * buffer);

/*
 * initsprites()
 *
 * Creates a table of values for sprite pasting.
 * Returns TRUE, or FALSE if error ocurred.
 */
long initsprites()
{
    long            i;
    g_planeoffsets = (long *) malloc(sizeof(long) * SPR_MAX_WIDTH);
    if (!g_planeoffsets) {
        fatalError("Malloc failed in initSprites");
    }
    for (i = 0; i < SPR_MAX_WIDTH; i += 4) {
        g_planeoffsets[i] = PLANESIZE * 0;
        g_planeoffsets[i + 1] = PLANESIZE * 1;
        g_planeoffsets[i + 2] = PLANESIZE * 2;
        g_planeoffsets[i + 3] = PLANESIZE * 3;
    }
    /* initshots(); */
    return (TRUE);
}

/*
 * loadsprites()
 *
 * Loads a sprite file from disk.  Use orange.exe to create a sprite
 * (.spr) file from pictures.
 */

int LoadSprites(char *name,long palettebase,long numcolors)
{
    int             fh;
    long            num = 0;
	struct stat fst;
	long    memorysize;
	char           *dataptr = (char *) NULL;
	sprite         *spr;
	char            errormsg[32];
	static char *palette = (char *) NULL;
	static long lastsize = 0;
	static char *sprdata = (char *) NULL;

    if((fh = open(name, O_RDONLY | O_BINARY)) < 0)
	 {
	  sprintf(errormsg,"Could not open %s \n",name);
	  fatalerror(errormsg);
	 }

	 //g_beginplay=1;
	 GetSpriteMemory(-1); //Initialize memory for the sprites

    /* Read and set color palette */
	 palette = GetSpriteMemory((numcolors *3));
     read(fh, palette, (numcolors * 3));

#if 1 
	if((!g_panelpalette) && (numcolors == 64) && (palettebase == 192))
	 {
       if(!(g_panelpalette = (char *) malloc(192)))
        fatalError("Malloc failed in loadsprite");
	 }

	 buffercopylongs(g_panelpalette,palette,(64 * 3));
#endif

    fstat(fh,&fst);
    memorysize=((fst.st_size-(numcolors * 3)) + (MAXSPRITES * sizeof(char *)));
    sprdata = (char *) GetSpriteMemory(memorysize);
	memset(sprdata,0,memorysize);
	spr     = sprdata;
	dataptr = sprdata + memorysize; //Point to the
	 							    //end of the memory
								    //chunk
     g_numsprites =0;
     g_ramsprites = (sprite *) sprdata;
    /* Read sprite data */
    while (read(fh, spr, (sizeof(sprite) - sizeof(char *)))) {

     dataptr -= spr->datasize; //Grab a slice of memory from the
		 					   //bottom of the chunk;
     if(dataptr < sprdata)
	  fatalerror("Error in memory allocation for sprites\n");

      spr->data = dataptr;
      read(fh,dataptr,spr->datasize);
	  (char *) spr += sizeof(sprite);
      ++g_numsprites;
    }

    
    close(fh);
    return TRUE;
}

long LoadTurnData(char *name)
{
  int fh;

  GetTurnMemory(-1);

  fh=open(name,O_RDONLY|O_BINARY);

  if(fh<0)
	return(0);

  if(!g_turntable)
	{
  	  g_turntable=GetTurnMemory(TURNMEMORYSIZE);
	  if(!g_turntable)
			fatalerror("Couldn't Malloc Turn Table");
	}
		
   read(fh,g_turntable,TURNMEMORYSIZE);
   close(fh);
   return(1);
}

#ifdef HEXAMON

/*
 * ResetSpritePalette()
 *
 * Sets the sprite palettes in case they are overrun
 */
void            ResetSpritePalette(u8 * where, long spritebase)
{
    setPalette(where, spritebase, SPRITECOLORS);
}

#ifdef HEXAMON
/*
 * plotshot
 *
 * Plots a shot into the current picture buffer
 */
void            plotshot(u8 * buffer, shotptr s)
{
    short           plane = s->curx & 3,
                    x = s->curx + g_newxoff,
                    y = s->cury + g_newyoff;
    if (x < 1 || x > 318 || y < 1 || y > 158)
        return;
    *(buffer + g_planeoffsets[plane] + x / 4 + y * PICWIDTH / 4) = s->color;
}
#endif

/*
 * print4
 *
 * prints to a blit4 picture buffer
 */

void print4(short x, short y, char *s, blitpicptr b)
{
    long            offset = (b->width / 4) * y;
    long            i,
                    len = strlen(s);

    for (i = 0; i < len; i++) {
        char            c = g_asciimap[s[i]];
        if (c) {
            long            d = (long) b->data;
            blitcharpanel(d + offset + x / 4, x & 3, (long) g_font[c - 1].data);
            x += g_font[c - 1].width;
        } else
            x += 4;             /* Blank character or space */
    }
}
#endif

/*
 * initanis()
 *
 * Initializes the animation structures
 */

void            initanis()
{
    int             i;
    for (i = 0; i < MAXANIS + 1; i++)   /* +1 because of our "fencepost" ani */
        g_ani[i].status = ANI_INACTIVE;

}

/*
 * startani()
 *
 * Starts an animation playing.  Returns FALSE if unsuccessful.
 */
int startani(spriteptr * s, short x, short y, long numframes, short dx, short dy)
{
    int             i = 0;
    while (g_ani[i].status != ANI_INACTIVE && i < MAXANIS)
        i++;
    if (i == MAXANIS)
        return (FALSE);
    g_ani[i].anibase = s;
    g_ani[i].x = x;
    g_ani[i].y = y;
    g_ani[i].dx = dx;
    g_ani[i].dy = dy;
    g_ani[i].numframes = numframes;
    g_ani[i].curframe = 0;
    g_ani[i].status = ANI_PLAYING;

    return TRUE;
}

/*
 * StartShot
 *
 * Starts a shot.  Returns FALSE if unable to.
 */
long            startshot(short x, short y, short tx, short ty, short numframes)
{
    long            i = 0;
    shotptr         s;

	 while (i < MAXSHOTS && g_shot[i].status != SHOT_INACTIVE)
        i++;
    if (i == MAXSHOTS)
        return (FALSE);

    x = x + g_windowx;
    y = y + g_windowy;
    tx = tx + g_windowx;
    ty = ty + g_windowy;
    s = &g_shot[i];
    s->curx = x;
    s->cury = y;
    s->destx = tx;
    s->desty = ty;
    s->dx = (tx - x) / numframes;
    s->dy = (ty - y) / numframes;
    s->frames = numframes;
    s->color = (i & 2) ? SHOTCOLOR : SHOTCOLOR + 1;
    s->status = SHOT_ACTIVE;
    return (TRUE);
}

/*
 * initshots
 *
 * Inits all the shot crapola.
 */
void            initShots()
{
    long            i;
//		 long col[2];
    for (i = 0; i < MAXSHOTS; i++)
        g_shot[i].status = SHOT_INACTIVE;
}

int loadblt(char *name, long palettebase, long numcolors, blitpicptr b)
{
	long            fp;
	long            i,rsize=0;
	long            len,blen = numcolors;
	short			nwidth,nheight;
	u8             *ptr;
	static u8       loc[768];
	static char     panelpalset=0;

	fp = open(name, O_RDONLY | O_BINARY);
	if (fp < 0)
		return (FALSE);

	if((!g_panelpalette) && (numcolors == 64) && (palettebase == 192))
	{
		panelpalset =0;
		if(!(g_panelpalette = (char *) malloc(192)))
			fatalError("Malloc failed in loadblt");
	}

	rsize = read(fp, loc, (numcolors * 3));
	blen =  (numcolors * 3);
	blen = blen << 16;
	++blen; //width == numcolors,  height = 1

	if((g_panelpalette) && (numcolors == 64) && (palettebase == 192) && (!panelpalset)) //I mean, why else ?
	{
		buffercopylongs(g_panelpalette,loc,(numcolors *3));
		panelpalset =1;
	}

	b->basecolor = palettebase;

    /* Read picture data */
	rsize+=read(fp, &nwidth, 2);
	rsize+=read(fp, &nheight, 2);

	nwidth  = nwidth ^ DECRYPTKEY;
	nheight = nheight ^ DECRYPTKEY;
	len = (nwidth * nheight);
    b->width  = nwidth;
	b->height = nheight;
	b->data   = (char *) GetBltMemory(len);
	b->map    = (char *) GetBltMemory((nwidth * nheight) / 4);

	if (!b->data) {
		fatalError("Malloc failed in loadblt");
	}

	rsize+=read(fp, b->data, len);
	rsize+=read(fp, b->map, ((b->width * b->height) / 4));
	close(fp);

	// Decrypt data (so those slimy users can't just load it!)
	ptr = b->data;
	for (i = 0; i < len; i++) {
		/**ptr=*ptr^DECRYPTKEY;*/
		ptr++;
	}
	return (TRUE);
}
pasteblt(u8 * buffer, blitpicptr b)
{
    long            row,
                    col;
    register u8    *to = buffer;
    register u8    *from = b->data;
    for (row = 0; row < b->height; row++) {
        for (col = 0; col < b->width; col++)
            *to++ = *from++;
        to += 320 - b->width;
    }
}

/*
 * printx(short x,short y,char *s)
 *
 * prints a text string to the screen at x,y (upper left)
 */


void            printx(short x, short y, char *s, u8 * buffer)
{
    long            i,
                    len = strlen(s);

    for (i = 0; i < len; i++) {
        char            c = g_asciimap[s[i]];
        if (c) {
            pastechar(&g_font[c], x, y, buffer);
            x += g_font[c].width;
        } else
            x += 4;             /* Blank character or space */
    }
}

pastechar(xfontptr f, short x, short y, u8 * buffer)
{
	register long   row, col;
	u8 *data = &f->data[0][0];

	buffer = buffer + 352 * y + x;
	for (row = 0; row < FHEIGHT; row++) 
	{
		for (col = 0; col < f->width; col++) 
		{
			if (*data)
//				*buffer = SHOTCOLOR + 1;        // 254;
				*buffer = g_textcol;
			buffer++;
			data++;
		}
		buffer += (352 - f->width);
		data += FWIDTH - f->width;
	}
}

/*
 * loadfont
 *
 * Just loads a .tff file (Tropical Font File)
 */

void loadfont(char *name)
{
    int fh;

    fh = open(name, O_RDONLY | O_BINARY);
    read(fh, &g_asciimap[0], 256);
    read(fh, &g_font[0], sizeof(xfont) * 256);
    close(fh);
}

// ------------------------------------------------------------------
//	pasteSpriteRAMwDAMG
//
// Paste a sprite from the data stream into the background.  Note that
// these are encoded slightly differently than RAM-resident (player)
// sprites, which call pastepsprite() instead.  Also note that this is
// not the most efficient function in the world.  An assembly-language
// version of this might be appropriate. This functions includes the
// damage pattern
//
// BTW, the sprites use a variation of run-length encoding.
// ------------------------------------------------------------------

#define DAMG_WIDTH		36
#define DAMG_HEIGHT		38

char pasteSpriteRAMwDAMG(spriteptr s,short x,short y,long targid,u8 * buffer)
{
    signed char  *to = buffer,*from = s->data;
    long  runcount,n, i;
    long  width = s->width;
    long  rows = s->height;
    long  curwidth = 0;
    char  buf[16];
	char 	 pat_x=0,pat_y =0;        

//    if (x < 0 || y < 0)         // Never hurts to be safe.
//        return(FALSE);

	if ((n=(rows+y)-160) >0)
		rows -=n;
	if (rows < 0)
		return(FALSE);

    g_damagedchannel = -1;
    to += 352 * y + x;  // Set up the initial address to start pasting
//	 if (to < buffer)
//	 	return(FALSE);
    while (rows) {
        if (*from < 0) {        // High bit set indicates a run of pixels
            runcount = 0 - *from++;
            if (*from) {        // Color 0 is considered transparent
                for (i = 0; i < runcount; i++)
                    {
					  if(g_damg.data[pat_x + (pat_y * DAMG_WIDTH)])
					  {
					   *to++ = g_weapcolors[g_selectedweap];
						}
						else 
						{
						   *to++ = *from;
						}
	               pat_x = (pat_x==(DAMG_WIDTH -1)) ? 0 : (pat_x + 1);
					}
            } else
                to += runcount;
            from++;
            curwidth += runcount;
        } else {                // Length of run of unique pixels
            runcount = *from++;
            for (i = 0; i < runcount; i++) {
                if (*from)
                    {
					  if(g_damg.data[pat_x + (pat_y * DAMG_WIDTH)])
					   {
					    *to++ = g_weapcolors[g_selectedweap];
						++from;
					   }
					  else 
					  *to++ = *from++;

					}
                else {
                    to++;
                    from++;
                }

		        pat_x = (pat_x==(DAMG_WIDTH -1)) ? 0 : (pat_x + 1);
            }
            curwidth += runcount;
        }
        if (curwidth >= width) {
            to += (352 - width);
            rows--;
			if(pat_y == (DAMG_HEIGHT -1))
			 pat_x=0;
		    pat_y =(pat_y==(DAMG_HEIGHT -1)) ? 0 : (pat_y + 1);
            curwidth = 0;
        }
    }
#ifdef DEBUGGING_ON
    sprintf(buf, "%ld", targid);
    printx(x, y, buf, buffer);
#endif
	 return(TRUE);
/* ---Uncomment this to see a green pixel in the corner of the bounding box
        to=buffer+352*y+x;
        *to=160;
        *(to+s->width)=160;
        *(to+352*s->height)=160;
        *(to+352*s->height+s->width)=160;
*/
}
// ------------------------------------------------------------------
//	pasteSpriteRAM
//
// Paste a sprite from the data stream into the background.  Note that
// these are encoded slightly differently than RAM-resident (player)
// sprites, which call pastepsprite() instead.  Also note that this is
// not the most efficient function in the world.  An assembly-language
// version of this might be appropriate.
//
// BTW, the sprites use a variation of run-length encoding.
// ------------------------------------------------------------------

char pasteSpriteRAM(spriteptr s, short x, short y, long targid, u8 * buffer)
{
	signed char *to = buffer, *from = s->data;
	long runcount, i;
	long width = s->width, rows = s->height;
	long curwidth = 0, n;
	char buf[16];

//    if (x < 0 || y < 0)         // Never hurts to be safe.
//        return(FALSE);
	if ((n=(rows+y)-160) >0)
		rows -=n;
	if (rows < 0)
		return(FALSE);
	to += 352 * y + x;   // Set up the initial address to start pasting
//	if (to < buffer)
//		return(FALSE);
	while (rows) 
	{
		if (*from < 0) 
		{        // High bit set indicates a run of pixels
			runcount = 0 - *from++;
			if (*from) 
			{        // Color 0 is considered transparent
				for (i = 0; i < runcount; i++)
					*to++ = *from;
			} 
			else
				to += runcount;
			from++;
			curwidth += runcount;
		} else {                // Length of run of unique pixels
			runcount = *from++;
			for (i = 0; i < runcount; i++) 
			{
				if (*from)
					*to++ = *from++;
				else 
				{
					to++;
					from++;
				}
			}
			curwidth += runcount;
		}
		if (curwidth >= width) 
		{
			to += (352 - width);
			rows--;
			curwidth = 0;
		}
	}
#ifdef DEBUGGING_ON
   sprintf(buf, "%ld", targid);
    printx(x, y, buf, buffer);
#endif
	 return(TRUE);
/* ---Uncomment this to see a green pixel in the corner of the bounding box
        to=buffer+352*y+x;
        *to=160;
        *(to+s->width)=160;
        *(to+352*s->height)=160;
        *(to+352*s->height+s->width)=160;
*/
}

// ---------------------------------------------------------------------
//  pastepsprite()
//
//  Pastes in player sprites, which are encoded slightly differently than
//  data-stream sprites.  These should really be called RAM-Resident sprites.
// ----------------------------------------------------------------------

void            pastepSprite(sprite s, short x, short y, u8 * buffer)
{
    u8             *to = buffer,
                   *from = s.data;
//	long runcount;
//	long i;
    long            row,
                    col;
    long            width = s.width;

    if (y < 0)
        return;
    if (x < 0) {                // This clips off stuff that goes off the
                                // left edge.
                                // / The right edge is still a danger.
        width += x;
        if (width > 0)
            x = 0;
        else
            return;
    }
    to += 352 * y + x;

    for (row = 0; row < s.height; row++) {
        from += (s.width) - width;
        for (col = 0; col < width; col++) {
            if (*from)
                *to++ = *from++;
            else {
                to++;
                from++;
            }
        }
        to += 352 - width;
    }
}

// -------------------------------------------------------------------
//	SpriteAddOnScreen()
//
//
//  Add Sprite to the on screen list.
// -------------------------------------------------------------------
void SpriteAddOnScreen(long spritenumb, TARGET * spritetarg)
{
    long            spritenumber = spritenumb,
                    y;
    TARGET         *targ;
#ifdef TESTADDON
    static FILE    *fp = (FILE *) NULL;
    if (fp == (FILE *) NULL)
        fp = fopen("test.aon", "wt");
#endif


    if (((spritenumb < 0) || (spritenumb > g_numtargets)) &&
        (spritetarg == (TARGET *) NULL))
        return;

    if (spritenumb < 0)
        spritenumber = (y = (((long) spritetarg - (long) &g_targstack[0]))) / ((long) sizeof(TARGET));

    if (g_targstack[spritenumber].status.state == (short) STATE_REST)
	 {
        g_targstack[spritenumber].status.state = (short) STATE_ALIVE;
        g_targstack[spritenumber].status.life  =
			 g_classtack[g_targstack[spritenumber].eclass].hitpoints;
 	 }

    if (g_targstack[spritenumber].status.state != (short) STATE_ALIVE)
        return;

	if(g_targstack[spritenumber].targettype == TARGET_TOOL)
	 {
	  if(g_targstack[spritenumber].toolweapclue < 0)
	   fatalerror("Illgally classified tool\n");

       if((g_targstack[spritenumber].toolweapclue < MAX_CYBTOOLS) &&
	      (g_tools[g_targstack[spritenumber].toolweapclue].toolaquired) &&
		  (g_currentscenenumber != SC_INWALL))
	       return;

       if((g_targstack[spritenumber].toolweapclue < MAX_CYBTOOLS) &&
	      ((g_targstack[spritenumber].toolweapclue == TL_Passcode1) &&
	       (g_tools[TL_Passcode2].toolaquired)))
		    return;
	 }

	if(g_targstack[spritenumber].targettype == TARGET_WEAP)
	 {
	  if(g_targstack[spritenumber].toolweapclue < 0)
	   fatalerror("Illgally classified weapon\n");
       if(g_weaps[g_targstack[spritenumber].toolweapclue].weapaquired)
	    return;

	   if((g_targstack[spritenumber].toolweapclue == WP_HexRipper1) &&
	      (g_weaps[WP_HexRipper2].weapaquired))
		    return;
	 }

    if (g_targstack[spritenumber].status.isonscreen == TRUE)
        return;

    if((g_targstack[spritenumber].endframe-g_targstack[spritenumber].startframe)
	 >=20)
    {
	 g_targstack[spritenumber].bracketcount  = NUMBRACKETS -1;
	 g_targstack[spritenumber].bracketwidth  = BRACKET_WIDTH;
	 g_targstack[spritenumber].bracketheight = BRACKET_HEIGHT;
	}
	else
	{
	 g_targstack[spritenumber].bracketcount  = 0;
	 g_targstack[spritenumber].bracketred	  = 3;
	 g_targstack[spritenumber].bracketwidth  = BRACKET_WIDTH_FIN;
	 g_targstack[spritenumber].bracketheight = BRACKET_HEIGHT_FIN;
	}

    // g_targstack[spritenumber].status.isonscreen = TRUE;
    // g_targstack[spritenumber].onscreen = g_SpritesOnScreen;
    // g_SpritesOnScreen  = &g_targstack[spritenumber];

    if ((g_SpritesOnScreen == (TARGET *) NULL) ||
        (g_targstack[spritenumber].channel < g_SpritesOnScreen->channel)) {
        g_targstack[spritenumber].status.isonscreen = TRUE;
        g_targstack[spritenumber].onscreen = g_SpritesOnScreen;
        g_SpritesOnScreen = &g_targstack[spritenumber];
        return;
    } 
	 else 
	 {
		for(targ=g_SpritesOnScreen;targ!=(TARGET *) NULL;targ=targ->onscreen) {
			if ((targ->onscreen == (TARGET *) NULL) ||
				(g_targstack[spritenumber].channel < targ->onscreen->channel)) {
				g_targstack[spritenumber].status.isonscreen = TRUE;
				g_targstack[spritenumber].onscreen = targ->onscreen;
				targ->onscreen = &g_targstack[spritenumber];
				return;
			}
		}
	}
}
// note: put this before the return in the previous if statement for testing.
#ifdef TESTADDON
        for (targ = g_SpritesOnScreen; targ != (TARGET *) NULL; targ = targ->onscreen)
            fprintf(fp, "%d ", targ->channel);
        fprintf(fp, "\n");

        if ((g_curframe > 200) && (g_scenentry[SC_CITYLT] > 1)) {
            fclose(fp);
            g_killgame = TRUE;
        }
#endif
// note: put this before the return in the previous if statement for testing.
#ifdef TESTADDON
        for (targ = g_SpritesOnScreen; targ != (TARGET *) NULL; targ = targ->onscreen)
            fprintf(fp, "%d ", targ->channel);
        fprintf(fp, "\n");

        if ((g_curframe > 200) && (g_scenentry[SC_CITYLT] > 1)) {
            fclose(fp);
            g_killgame = TRUE;
        }
#endif
// -------------------------------------------------------------------
//	SpriteDelOnScreen()
//
//
//  Delete Sprites from the on screen list.
// -------------------------------------------------------------------
TARGET *SpriteDelOnScreen(TARGET * spritetodel)
{
    TARGET  *targ;

    if (spritetodel == (TARGET *) NULL)
        return ((TARGET *) NULL);

    if ((spritetodel->type == 'lrcr') ||        // Special case for DATA
                                                // Cleansing
        (spritetodel->type == 'cbox'))
         spritetodel->status.state = (short)STATE_SLEEP;

    if ((spritetodel->type == 'lcir') ||
        (spritetodel->type == 'rcir'))  // Special case for DATA Cleansing
        spritetodel->status.state = (short)STATE_ALIVE;


    if (spritetodel == g_SpritesOnScreen) {
        g_SpritesOnScreen = g_SpritesOnScreen->onscreen;
        spritetodel->status.isonscreen = FALSE;
        spritetodel->status.explosioncount = -1;
        spritetodel->status.explosionsize  = -1;
		return(g_SpritesOnScreen);
    } else {
        for (targ = g_SpritesOnScreen; targ != (TARGET *) NULL; targ = targ->onscreen)
            if (targ->onscreen == spritetodel) {
                targ->onscreen = targ->onscreen->onscreen;
                spritetodel->onscreen = (TARGET *) NULL;
                spritetodel->status.isonscreen = FALSE;
                spritetodel->status.explosionsize  = -1;
                spritetodel->status.explosioncount = -1;
                return (targ->onscreen);
            }
    }
    return ((TARGET *) NULL);
}

// -------------------------------------------------------------------
//	SpritePlaceOnScreen()
//
// Paste in the sprites  that are on the on scree list.
//
// -------------------------------------------------------------------

void SpritePlaceOnScreen(u8 * smackerbuf)
{
	long  ul,ur,ll,lr,x1=0,x2=0,y1=0,y2=0,tx,ty;
	TARGET *targ = g_SpritesOnScreen;
	long    explframe, fireframe, nexplfr, damage;
	char abovepanel = TRUE;

	g_imagebuffer = smackerbuf;

	nexplfr = (g_currentscenenumber > SC_GRWALL) ? NUMCYBEXPLFRAMES : NUMRWDEXPLFRAMES;

	while (targ != (TARGET *) NULL) 
	{
		if ((g_curframe < targ->startframe) || (g_curframe > targ->endframe)) 
		{
			targ = SpriteDelOnScreen(targ);
			continue;
		} 
		else 
		{
			if (g_pastein[targ->channel].spritedata == NULL)
				fatalError("Event file CTARS do not match smack file\n");
			if (targ->status.state == (short)STATE_ALIVE) 
			{
				if((g_currentscenenumber > SC_GRWALL) && (targ->bracketcount))
					g_targetcolor = cyb_targetingcol;
				else
					g_targetcolor = rel_targetingcol;

				if(!targ->bracketcount)
				{
					if(g_currentscenenumber > SC_GRWALL)
					{
						if(targ->bracketred)
						{
							g_targetcolor = cyb_targetflash;
							--targ->bracketred;
						}
						else
						{
							g_targetcolor = cyb_targetedcol;
						}
					}
					else
					{
						if(targ->bracketred)
						{
							g_targetcolor = rel_targetflash;
							--targ->bracketred;
						}
						else
						{
							g_targetcolor = rel_targetedcol;
						}
					}
				}

				if(targ->toolweapclue > -1)
					g_targetcolor = cyb_targettoolcol;

				x1 =x2 =y1 =y2 =0;
				tx =  (g_pastein[targ->channel].x - g_savewindowx);
				ty =  (g_pastein[targ->channel].y - g_savewindowy);
				tx += (g_pastein[targ->channel].spritedata->width >> 1);
				ty += (g_pastein[targ->channel].spritedata->height >>1);

				if(targ->channel != g_damagedchannel)
					abovepanel = pasteSpriteRAM(g_pastein[targ->channel].spritedata,
								(g_pastein[targ->channel].x - g_savewindowx),
								(g_pastein[targ->channel].y - g_savewindowy),
								targ->id,
								smackerbuf);
				else
					abovepanel = pasteSpriteRAMwDAMG(g_pastein[targ->channel].spritedata,
								(g_pastein[targ->channel].x - g_savewindowx),
								(g_pastein[targ->channel].y - g_savewindowy),
								targ->id,
								smackerbuf);

				if(targ->targetable == TRUE && abovepanel == TRUE)
				{
					x1=((tx-targ->bracketwidth)<0) ? 0 : (tx-targ->bracketwidth);
					x2=((tx+targ->bracketwidth)>319) ? 319:(tx+targ->bracketwidth);
					y1=((ty-targ->bracketheight)<0) ? 0 : (ty-targ->bracketheight);
					y1=((y1>156) ? 156 : y1);
					y2=((ty+targ->bracketheight)>158) ? 158 :(ty+targ->bracketheight);
//					y2=((ty+targ->bracketheight)>319) ? 319 :(ty+targ->bracketheight);
				  //Upper left and right
					ul = (x1 + (y1 * 352));
					ur = (x2 + (y1 * 352)) -4;

                //Lower left and right
					ll = (x1 + (y2 * 352));
					lr = (x2 + (y2 * 352)) -4;

					bufferpastesquare(ul,ur,ll,lr);

					if(targ->bracketcount)
					{
						--targ->bracketcount;
						if (targ->bracketcount == 0)
							targ->bracketred = 4;
						targ->bracketwidth -=BRACKET_X_SUB;
						targ->bracketheight-=BRACKET_Y_SUB;
					}
					else
					{
						if(targ->toolweapclue > -1)
							g_targetcolor = cyb_targettoolcol;
						else
							g_targetcolor = cyb_targetedcol;

						targ->bracketwidth =BRACKET_WIDTH_FIN;
						targ->bracketheight=BRACKET_HEIGHT_FIN;
					}
				}

				if (targ->numfires) 
				{
					for (fireframe = 0; fireframe < targ->numfires; ++fireframe)
					{
						if (targ->fframes[fireframe] == g_curframe) 
						{
							if (targ->type == 'recn')
								playSoundFX(S_RECONGUN);
							if (targ->type == 'ball')
								playSoundFX(S_LIGHTNING);

							damage  =  g_classtack[targ->eclass].damage;

							if (g_currentscenenumber == SC_GRWALL)
								damage *=  g_powrmult;
							else if((!g_tools[TL_DamageRepair].toolaquired) &&
										(g_currentscenenumber > SC_INFNET))
								damage *=  g_shotmult;
							  
							if ((g_player.hitpoints -= damage) < 0)
								g_player.hitpoints = 0;

							if (g_currentscenenumber == SC_CANYON)
							{
								if (targ->type == 'fort')
									g_typeofdeath = CN_DEATH_BY_COLLISION;
								else
									g_typeofdeath = CN_DEATH_BY_SHOT;
							}
							else if (g_currentscenenumber == SC_GRWALL) 
							{
								if (targ->type == '2jet')
									g_typeofdeath = GW_DEATH_BY_PLANE;
								else
									g_typeofdeath = GW_DEATH_BY_CANON;
							} 
							else if (g_currentscenenumber == SC_DATACL) 
							{
								if (targ->type == 'dogy')
									g_typeofdeath = DC_DEATH_BY_DOGY;
								else if (targ->type == 'miss')
									g_typeofdeath = DC_DEATH_BY_MISSLE;
								else if ((targ->type == 'lcir') ||
											(targ->type == 'rcir') ||
											(targ->type == 'cbox'))
									g_typeofdeath = DC_DEATH_BY_DELETER;
								else if (targ->type == 'ifrc')
									g_typeofdeath = DC_DEATH_BY_ICONHALLS;
							} 
							else if (g_currentscenenumber == SC_PDEFEN) 
							{
								if (targ->type == 'clos')
									g_typeofdeath = PD_DEATH_BY_CRUSH;
								else if((targ->id == 7)  ||
										 (targ->id == 8)  ||
										 (targ->id == 14) ||
										 (targ->id == 15) ||
										 (targ->id == 16) ||
										 (targ->id == 18))
									g_typeofdeath = PD_DEATH_BY_WALLSHOOTER;
								else
									g_typeofdeath = PD_DEATH_BY_GENERALSHOT;
							} 
							else if (g_currentscenenumber == SC_INWALL) 
							{
								if (targ->type == 'dogy' || targ->type == 'turr')
									g_typeofdeath = IW_DEATH_BY_TRAILDOGY;
								else if (targ->type == 'dtag')
									g_typeofdeath = IW_DEATH_BY_BIGKUDJO;
								else if (targ->type == 'sadf')
									g_typeofdeath = IW_DEATH_BY_SADFORCEP;
								else if (targ->type == 'torn')
									g_typeofdeath = IW_DEATH_BY_TORNADO;
							}
						}
					}
				}
			} 
			else if (targ->status.explosioncount > 0) 
			{
				explframe  = targ->status.explosionsize;
				explframe +=(nexplfr - targ->status.explosioncount);
				pastepSprite(g_ramsprites[explframe],
								(g_pastein[targ->channel].x - g_savewindowx),
								(g_pastein[targ->channel].y - g_savewindowy),
								smackerbuf);
				--targ->status.explosioncount;
			}
			targ = targ->onscreen;
		}
	}
}


void *GetSpriteMemory(long amtreq)
{
 static void *freemempntr,*retmempntr;
 char *errormsg1 = "Not enough memory for Firewall sprites\n";
 char *errormsg2 = "Availible Firewall sprite memory exceeded\n";

 if(g_spritememory == (void *) NULL)
    if(!(g_spritememory = (void *) malloc(SPRITEMEMORYSIZE)))
      fatalerror(errormsg1);

  if(amtreq < 0)
    {
	 retmempntr  = g_spritememory;
	 freemempntr = g_spritememory;
	 memset(g_spritememory,0,SPRITEMEMORYSIZE);
	 return((void *) NULL);
	}

  if(!amtreq)
	return((void *) NULL);

  if(((char *) freemempntr + amtreq) > ((char *) g_spritememory + SPRITEMEMORYSIZE))
     fatalerror(errormsg2);

  retmempntr = freemempntr;
  (char*) freemempntr+=amtreq;

  return(retmempntr);
}

void *FreeSpriteMemory(void)
 {
 if(g_spritememory != (void *) NULL)
  free(g_spritememory);
  g_spritememory=(void *) NULL;
 }

void *GetBltMemory(long amtreq)
{
 static void *freemempntr,*retmempntr;
 char *errormsg1 = "Not enough memory for Firewall blt files\n";
 char *errormsg2 = "Availible Firewall blt memory exceeded\n";

 if(g_bltmemory == (void *) NULL)
    if(!(g_bltmemory = (void *) malloc(BLTMEMORYSIZE)))
      fatalerror(errormsg1);

  if(amtreq < 0)
    {
	 retmempntr  = g_bltmemory;
	 freemempntr = g_bltmemory;
	 memset(g_bltmemory,0,BLTMEMORYSIZE);
	 return((void *) NULL);
	}

  if(!amtreq)
	return((void *) NULL);

  if(((char *) freemempntr + amtreq) > ((char *) g_bltmemory + BLTMEMORYSIZE))
     fatalerror(errormsg2);

  retmempntr = freemempntr;
  (char*) freemempntr+=amtreq;

  return(retmempntr);
}

void *FreeBltMemory(void)
 {
 if(g_bltmemory != (void *) NULL)
  free(g_bltmemory);
 g_bltmemory=(void *) NULL;
 }

void *GetTurnMemory(long amtreq)
{
 static void *freemempntr,*retmempntr;
 char *errormsg1 = "Not enough memory for Firewall turn data files\n";
 char *errormsg2 = "Availible Firewall turn memory exceeded\n";

 if(g_turnmemory == (void *) NULL)
    if(!(g_turnmemory = (void *) malloc(TURNMEMORYSIZE)))
      fatalerror(errormsg1);

  if(amtreq < 0)
    {
	 retmempntr  = g_turnmemory;
	 freemempntr = g_turnmemory;
	 memset(g_turnmemory,0,TURNMEMORYSIZE);
	 return((void *) NULL);
	}

  if(!amtreq)
	return((void *) NULL);

  if(((char *) freemempntr + amtreq) > ((char *) g_turnmemory + TURNMEMORYSIZE))
     fatalerror(errormsg2);

  retmempntr = freemempntr;
  (char*) freemempntr+=amtreq;

  return(retmempntr);
}

void *FreeTurnMemory(void)
 {
 if(g_turnmemory != (void *) NULL)
  free(g_turnmemory);
 g_turnmemory=(void *) NULL;
 }

